/*
 * @(#)KeepAliveStream.java	1.22 06/10/10
 *
 * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved.  
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER  
 *   
 * This program is free software; you can redistribute it and/or  
 * modify it under the terms of the GNU General Public License version  
 * 2 only, as published by the Free Software Foundation.   
 *   
 * This program is distributed in the hope that it will be useful, but  
 * WITHOUT ANY WARRANTY; without even the implied warranty of  
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  
 * General Public License version 2 for more details (a copy is  
 * included at /legal/license.txt).   
 *   
 * You should have received a copy of the GNU General Public License  
 * version 2 along with this work; if not, write to the Free Software  
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  
 * 02110-1301 USA   
 *   
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa  
 * Clara, CA 95054 or visit www.sun.com if you need additional  
 * information or have any questions. 
 *
 */

package sun.net.www.http;

import java.net.URL;
import java.io.*;
import sun.net.www.MeteredStream;
import sun.net.ProgressData;
import sun.net.ProgressEntry;

/**
 * A stream that has the property of being able to be kept alive for
 * multiple downloads from the same server.
 *
 * @version 1.22, 10/10/06 
 * @author Stephen R. Pietrowicz (NCSA)
 * @author Dave Brown
 */
public
class KeepAliveStream extends MeteredStream implements Hurryable {

    // instance variables
    HttpClient hc;

    boolean hurried;

    /**
     * Constructor
     */
    public KeepAliveStream(InputStream is, ProgressEntry te, HttpClient hc) {
	super(is, te);
	this.hc = hc;
    }

    /**
     * Attempt to cache this connection
     */
    public void close() throws IOException {
	// If the inputstream is closed already, just return.
	if (closed) {
	    return;
	}

	// Skip past the data that's left in the Inputstream because
	// some sort of error may have occurred.
	// Do this ONLY if the skip won't block. The stream may have
	// been closed at the beginning of a big file and we don't want
	// to hang around for nothing. So if we can't skip without blocking
	// we just close the socket and, therefore, terminate the keepAlive
	// NOTE: Don't close super class
	try {
	    if (expected > count) {
		long nskip = (long) (expected - count);
		if (nskip <= available()) {
		    long n = 0;
		    while (n < nskip) {
			nskip = nskip - n;
			n = skip(nskip);		    
		    }
		} else {
		    hc.closeServer();
		}
	    }          
	    if (!closed && !hurried) {
		hc.finished();
	    }
	} finally {
	    ProgressData.pdata.unregister(te);
	    // nulling out the underlying inputstream as well as
	    // httpClient to let gc collect the memories faster
	    in = null;
	    hc = null;
	    closed = true;
	}
    }

    /* we explicitly do not support mark/reset */

    public boolean markSupported() {
	return false;
    }

    public void mark(int limit) {}

    public void reset() throws IOException {
	throw new IOException("mark/reset not supported");
    }

    public synchronized boolean hurry() {
	try {
	    /* CASE 0: we're actually already done */
	    if (closed || count >= expected) {
		return false;
	    } else if (in.available() < (expected - count)) {
		/* CASE I: can't meet the demand */
		return false;
	    } else {
		/* CASE II: fill our internal buffer
		 * TODO: possibly check memory here
		 */
		byte[] buf = new byte[expected - count];
		DataInputStream dis = new DataInputStream(in);
		dis.readFully(buf);
		in = new ByteArrayInputStream(buf);
		hurried = true;
		return true;
	    }
	} catch (IOException e) {
	    // e.printStackTrace();
	    return false;
	}
    }
}



